home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / wais / ui / lisp-ui.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  10KB  |  374 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4.  
  5.    Brewster@think.com
  6. */
  7.  
  8.  
  9. /* This is a simple wais interface for lisp clients.
  10.  * It takes in lisp-y looking requests and sends out Z39.50 packets.
  11.  *
  12.  * -brewster 7/90
  13.  *
  14.  * Important functions:
  15.  *   display_search_response
  16.  *   main
  17.  */
  18.  
  19. #include <stdio.h>
  20. #include <ctype.h>
  21. #include <string.h>
  22. #include "../ir/ui.h"
  23.  
  24. #define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
  25. #define MAX_MESSAGE_LEN BUFSZ
  26. #define VERBOSE false /* true */
  27.  
  28. /****************************************************************
  29.  *
  30.  *         Function Name:  display_search_response
  31.  *
  32.  *
  33.  *     Purpose: displays the formatted list of documents in the form  
  34.  *               that the super-text-server would like to see. 
  35.  *
  36.  *     Returns: nothing.
  37.  *
  38.  *    Algorithm:   . ...
  39.  *
  40.  */
  41.  
  42.  
  43. /* modified from tracy shen's version in wutil.c
  44.  * displays a set of headlines.
  45.  */
  46. void
  47. display_search_response(response,database,server_name,service_name)
  48. SearchResponseAPDU *response;
  49. char *database;
  50. char *server_name;
  51. char *service_name;
  52. {
  53.   WAISSearchResponse  *info;
  54.   long k;
  55.   printf("(:query (");
  56.  
  57.   if ( response->DatabaseDiagnosticRecords != 0 ) {
  58.     info = response->DatabaseDiagnosticRecords;
  59.     if(info->DocHeaders != 0){
  60.       k =0;
  61.       while(info->DocHeaders[k] != 0 ){       
  62.     char doc_id[1000];
  63.     strncpy(doc_id,    info->DocHeaders[k]->DocumentID->bytes,
  64.         MIN(info->DocHeaders[k]->DocumentID->size, 1000));
  65.     doc_id[MIN(info->DocHeaders[k]->DocumentID->size, 1000 - 1)] 
  66.       = '\0';
  67.     printf("(:doc-id \"%s\" :document-length %ld :types (\"%s\") :database-name \"%s\" :server-name \"%s\" :score %ld :service \"%s\" :header \"",
  68.            doc_id,
  69.            info->DocHeaders[k]->DocumentLength,
  70.            (info->DocHeaders[k]->Types == NULL)?"TEXT":info->DocHeaders[k]->Types[0],
  71.            database,
  72.            server_name,
  73.            info->DocHeaders[k]->Score,
  74.            service_name
  75.            );
  76.     { char *header = trim_junk(info->DocHeaders[k]->Headline);
  77.       long i;
  78.       for(i=0; i < strlen(header); i++){
  79.         char ch = header[i];
  80.         if(ch == '"')
  81.           putc('\\', stdout);
  82.         putc(ch, stdout);
  83.       }
  84.     }
  85.     printf("\")");
  86.     k++;
  87.       }
  88.     }
  89.   }
  90.   printf(")\n:end t)\n");    /* finish it */
  91.   fflush(stdout);
  92. }
  93.  
  94.  
  95. /*******************
  96.  *     Parsing     *
  97.  *******************/
  98.  
  99. /* In a alist of keys and values,
  100.  * this finds the string value associated with a key.
  101.  * The way this is implemented is a kludge since it searches for
  102.  * the key with string search rather than making a list and
  103.  * searching down it.  This can error if a value contains a string version
  104.  * of the key.
  105.  * What we really need is list facilities.
  106.  *
  107.  * Side effects value.
  108.  * Returns 0 if it wins, 1 if there is no such slot, -1 if error.
  109.  */
  110.  
  111. /* these are states of the parser */
  112. #define BEFORE 1
  113. #define DURING 2
  114. #define QUOTE 5
  115.  
  116. long find_string_slot(source,key,value,value_size,delete_internal_quotes)
  117. char *source;
  118. char *key;
  119. char *value;
  120. long value_size;
  121. boolean delete_internal_quotes;
  122. {
  123.   char ch;
  124.   short state = BEFORE;
  125.   long position = 0;  /* position in value */
  126.   char *pos =strstr(source, key); /* address into source */
  127.  
  128.   value[0] = '\0';        /* initialize to nothing */
  129.  
  130.   if(NULL == pos)
  131.     return(1);
  132.  
  133.   for(pos = pos + strlen(key); pos < source + strlen(source); pos++){
  134.     ch = *pos;
  135.     if((state == BEFORE) && (ch == '\"'))
  136.       state = DURING;
  137.     else if ((state == DURING) && (ch == '\\')){
  138.       state = QUOTE;    
  139.       if(!delete_internal_quotes){
  140.     value[position] = ch;
  141.     position++;
  142.     if(position >= value_size){
  143.       value[value_size - 1] = '\0';
  144.       return(-1);
  145.     }
  146.       }
  147.     }
  148.     else if ((state == DURING) && (ch == '"')){    
  149.       value[position] = '\0';
  150.       return(0);
  151.     }
  152.     else if ((state == QUOTE) || (state == DURING)){
  153.       if(state ==  QUOTE)
  154.     state = DURING;
  155.       value[position] = ch;
  156.       position++;
  157.       if(position >= value_size){
  158.     value[value_size - 1] = '\0';
  159.     return(-1);
  160.       }
  161.     }
  162.     /* otherwise we are still before the start of the value */
  163.   }
  164.   value[position] = '\0';
  165.   return(-1); /* error because we are in the middle of the string */
  166. }
  167.  
  168. /* reads a long int a file returns true if successful, false otherwise */
  169. long find_long_slot(source,key,answer)
  170. char *source;
  171. char *key;
  172. long *answer;
  173. {
  174.   char ch;
  175.   short state = BEFORE;
  176.   char *pos =strstr(source, key); /* address into source */
  177.   long count = 0;
  178.   boolean isNegative = false;
  179.   *answer = 0;
  180.  
  181.   if(NULL == pos)
  182.     return(1);
  183.  
  184.   for(pos = pos + strlen(key); pos < source + strlen(source); pos++){
  185.     ch = *pos;
  186.     if (isdigit(ch)){
  187.       if(state == BEFORE){
  188.     state = DURING;
  189.       }
  190.       count++;
  191.       if(count == 12){
  192.     /* then we have an error in the file, 32 bit numbers can not be more
  193.        than 10 digits long */
  194.     return(-1);
  195.       }
  196.       *answer = *answer * 10 + (ch - '0');
  197.     }
  198.     else if (ch == '-') {
  199.       if (isNegative)
  200.     /* then we have an error since there should be only one - in a number */
  201.     return(-1);
  202.       if (state == BEFORE) {
  203.     /* we are ok since the - must come before any digits */
  204.     isNegative = true;
  205.     state = DURING;
  206.       }
  207.       else {
  208.     break;            /* we are done */
  209.       }
  210.     }
  211.     else if(!isspace(ch)){
  212.       /* then we have an error since it should be a digit or a space */
  213.       return(-1);
  214.     }
  215.     /* we do not have an digit */
  216.     else if(state == DURING){
  217.       break;            /* we are done */
  218.     }
  219.     /* otherwise we are still before the start */
  220.   }
  221.   if (isNegative)
  222.     *answer *= -1;
  223.   return(0);
  224. }
  225.  
  226.  
  227.  
  228. /************
  229.  *   MAIN   *
  230.  ************/
  231.  
  232. #define MAX_QUERY_SIZE 10000
  233. #define MAX_NAME_SIZE 1000
  234. void main()
  235. {
  236.   char query[MAX_QUERY_SIZE + 1];
  237.   char request_message[MAX_MESSAGE_LEN]; /* arbitrary message limit */
  238.   char response_message[MAX_MESSAGE_LEN]; /* arbitrary message limit */
  239.   long request_buffer_length;    /* how of the request is left */
  240.   SearchResponseAPDU  *query_response;
  241.   SearchResponseAPDU  *retrieval_response;
  242.   char service[MAX_NAME_SIZE + 1];
  243.   char database[MAX_NAME_SIZE + 1];
  244.   char server_name[MAX_NAME_SIZE + 1];
  245.   char type[MAX_NAME_SIZE + 1];
  246.  
  247.   server_name[0] = '\0';    /* null it out */
  248.   database[0] = '\0';        /* null it out */
  249.   service[0] = '\0';        /* null it out */
  250.  
  251.   while(TRUE){
  252.     /* continue to search until the user gets tired */
  253.  
  254.     fgets(query, MAX_QUERY_SIZE, stdin);
  255.     if(NULL != strstr(query, ":fill-in") ||
  256.        NULL != strstr(query, ":query")){
  257.       /* then we have a fill-in or query. 
  258.      extract the common fields */
  259.  
  260.       if(0 > find_string_slot(query, ":database", database,
  261.                   MAX_NAME_SIZE, false)){
  262.     panic("Could not read the database from query %s", query);
  263.       }
  264.       if(0 > find_string_slot(query, ":server", server_name,
  265.                   MAX_NAME_SIZE, false)){
  266.     panic("Could not read the host from query %s", query);
  267.       }
  268.       if(0 > find_string_slot(query, ":service", service,
  269.                   MAX_NAME_SIZE, false)){
  270.     panic("Could not read the service from query %s", query);
  271.       }
  272.     }
  273.  
  274.     if(NULL != strstr(query, ":fill-in")){
  275.       /* then we have a fill-in request */
  276.       long count;
  277.       long document_length;
  278.       char doc_id[MAX_NAME_SIZE + 1];
  279.       any doc_id_any;
  280.       if(0 != find_string_slot(query, ":doc-id", doc_id,
  281.                    MAX_NAME_SIZE, false)){
  282.     panic("Could not read the doc-id from request %s", query);
  283.       }
  284.       doc_id_any.bytes = doc_id;
  285.       doc_id_any.size = strlen(doc_id);
  286.  
  287.       if(0 != find_long_slot(query, ":document-length", &document_length)){
  288.     panic("Could not read the document length from doc_id %s", query);
  289.       }
  290.       if(0 != find_string_slot(query, ":type", type,
  291.                    MAX_NAME_SIZE, false)){
  292.     panic("Could not read the type from request %s", query);
  293.       }
  294.  
  295.       printf("(:fill-in (:text \""); /* start the reply */
  296.       for(count = 0; 
  297.       count * CHARS_PER_PAGE < document_length;
  298.       count++){
  299.     request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
  300.     if(NULL ==
  301.        generate_retrieval_apdu(request_message + HEADER_LENGTH,
  302.                    &request_buffer_length, 
  303.                    &doc_id_any,
  304.                    CT_byte,
  305.                    count * CHARS_PER_PAGE,
  306.                    MIN((count + 1) * CHARS_PER_PAGE, 
  307.                        document_length),
  308.                    type,
  309.                    database
  310.                    ))
  311.       panic("query was too large");
  312.     
  313.     if(0 ==
  314.        interpret_message(request_message, 
  315.                  MAX_MESSAGE_LEN - request_buffer_length, 
  316.                  response_message,
  317.                  MAX_MESSAGE_LEN,
  318.                  server_name, 
  319.                  service, 
  320.                  VERBOSE
  321.                  ))
  322.       panic("return message too large");
  323.  
  324.     readSearchResponseAPDU(&retrieval_response, 
  325.                    response_message + HEADER_LENGTH);
  326.     if(NULL == ((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text)
  327.       panic("No text was returned");
  328.  
  329.     display_text_record_completely
  330.       (((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text[0], true);
  331.       }
  332.       printf("\")\n:end t)\n");    /* finish the text */
  333.       fflush(stdout);
  334.     }
  335.     else if(NULL != strstr(query, ":query")){
  336.       /* then we have a query */
  337.       char seed_words[MAX_QUERY_SIZE + 1];
  338.       if(0 != find_string_slot(query, ":seed-words", seed_words,
  339.                    MAX_QUERY_SIZE, false)){
  340.     panic("Could not read the seed words from query %s", query);
  341.       }
  342.       request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
  343.       if(NULL ==
  344.      generate_search_apdu(request_message + HEADER_LENGTH, 
  345.                   &request_buffer_length, 
  346.                   seed_words, database, NULL))
  347.     panic("Query was too large");
  348.      
  349.       if(0 ==
  350.      interpret_message(request_message,
  351.                MAX_MESSAGE_LEN - request_buffer_length, 
  352.                response_message,
  353.                MAX_MESSAGE_LEN,
  354.                server_name, 
  355.                service,
  356.                VERBOSE
  357.                ))
  358.     panic("return message too large");
  359.  
  360.       readSearchResponseAPDU(&query_response, 
  361.                  response_message + HEADER_LENGTH);
  362.       display_search_response(query_response, database, server_name,
  363.                   service);
  364.     }
  365.     else
  366.       panic("Dont know how to handle query %s\n", query);
  367.   }
  368. }
  369.     
  370.   
  371. /* sample
  372. (:query :seed-words ("food") :database "/u/kahle/wais-index-irn8/foo" :server "gandalf" :service "8000")
  373. */
  374.